using System;
using System.Collections.Generic;
using WDFactoryLib;

namespace CardsEngine.TestKit
{
	public sealed class BasicDeckGenerator: FactoryUser, IDeckGenerator
	{
        private static readonly IShuffler DefaultShuffler;

        public static readonly BasicDeckGenerator Default;

		private IShuffler shuffler;

		static BasicDeckGenerator()
		{
			DefaultShuffler = BasicShuffler.Default;
            Default = new BasicDeckGenerator();
		}

        public BasicDeckGenerator()
            :base()
        {
            shuffler = DefaultShuffler;
        }

        public BasicDeckGenerator(IShuffler _shuffler)
            :base()
        {
            shuffler = _shuffler;
        }

        internal BasicDeckGenerator(IFactory _factory)
            :base(_factory)
        {
            shuffler = DefaultShuffler;
        }

        internal BasicDeckGenerator(IFactory _factory, IShuffler _shuffler)
            :base(_factory)
        {
            shuffler = _shuffler;
        }

		private static void GetFaceLimits (Card.AceMode aceMode, out int minFace, out int maxFace)
		{
			switch (aceMode) {
			case Card.AceMode.ACES_HIGH:
				minFace = (int)Card.Face.TWO;	
				maxFace = (int)Card.Face.HIGH_ACE;
				break;

			case Card.AceMode.ACES_LOW:
				minFace = (int)Card.Face.LOW_ACE;
				maxFace = (int)Card.Face.KING;
				break;

			default:
				throw new NotImplementedException("Support for the specified AceMode not implemented in DefaultDeckGenerator");
			}
		}

		private static void PopulateDeck (ICollection<Card> deck, int minFace, int maxFace)
		{
            Card tmp;

			for (int suitValue=Card.Suit.MINIMUM_INT_VALUE; suitValue<=Card.Suit.MAXIMUM_INT_VALUE; suitValue++)
				for (int faceValue=minFace; faceValue<=maxFace; faceValue++) {
					tmp = new Card((Card.Face)faceValue,(Card.Suit)suitValue);
					deck.Add (tmp);
				}
		}

        public IList<Card> GenerateUnshuffledDeck()
        {
            return GenerateUnshuffledDeck(Card.AceMode.ACES_HIGH);
        }

		public IList<Card> GenerateUnshuffledDeck (Card.AceMode aceMode)
		{
			int minFace, maxFace;
            IList<Card> deck = Factory.GetNewList<Card>(52);

			GetFaceLimits(aceMode, out minFace, out maxFace);

			PopulateDeck(deck, minFace, maxFace);

			return deck;
		}

        public IList<Card> GenerateShuffledDeck()
        {
            return GenerateShuffledDeck(Card.AceMode.ACES_HIGH);
        }

		public IList<Card> GenerateShuffledDeck (Card.AceMode aceMode)
		{
			IList<Card> deck = GenerateUnshuffledDeck(aceMode);

			shuffler.Shuffle(deck);

			return deck;
		}
	}
}

